package com.xinqi.modules.sys.gpt.util;

import com.alibaba.fastjson.JSONObject;
import com.xinqi.common.core.constant.Constants;
import com.xinqi.common.core.utils.StringUtils;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @version V1.0
 * @Title: 通用http发送方法
 * @ClassName: com.xinqi.modules.sys.gpt.util.HttpUtils.java
 * @Description:
 * @Copyright 星齐科技（云南）有限公司 - Powered By 技术部
 * @author: yyzhen
 * @date: 2023/5/29 8:45
 */
@Log4j2
public class HttpUtils {

    /**
     * 实体类对象转URL参
     *
     * @param t   实体类对象
     * @param <T> 实体类泛型
     * @return a=1&b=2
     */
    public static <T> String entityToUrlParam(T t) {
        // URL 参数存储器
        StringBuffer urlParam = new StringBuffer();
        if (!t.getClass().equals(Object.class)) {
            //获取实体类对象下的所有成员，并保存到 URL 参数存储器中
            Arrays.stream(t.getClass().getDeclaredFields()).forEach(field -> {
                //设置可以操作私有成员
                field.setAccessible(true);
                try {
                    //获取成员值
                    Object value = field.get(t);
                    //成员值为 Null 时，则不处理
                    if (Objects.nonNull(value) && StringUtils.isNotEmpty(value.toString())) {
                        urlParam.append(field.getName()).append("=").append(value).append("&");
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            });
        }
        if (urlParam.length() > 0) {
            //去除最后一个&字符
            urlParam.deleteCharAt(urlParam.length() - 1);
        }
        return urlParam.toString();
    }

    public static <T> Map<String, Object> entityToMap(T t) {
        // URL 参数存储器
        Map<String, Object> map = new HashMap<String, Object>();
        if (!t.getClass().equals(Object.class)) {
            //获取实体类对象下的所有成员，并保存到 URL 参数存储器中
            Arrays.stream(t.getClass().getDeclaredFields()).forEach(field -> {
                //设置可以操作私有成员
                field.setAccessible(true);
                try {
                    //获取成员值
                    Object value = field.get(t);
                    //成员值为 Null 时，则不处理
                    if (Objects.nonNull(value) && StringUtils.isNotEmpty(value.toString())) {
                        map.put(field.getName(), value);
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            });
        }
        return map;
    }

    /**
     * 向指定 URL 发送GET方法的请求
     *
     * @param url   发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param, String token) {
        StringBuilder result = new StringBuilder();
        BufferedReader in = null;
        try {
            String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
            //log.info("sendGet - {}", urlNameString);
            URL realUrl = new URL(urlNameString);
            URLConnection connection = realUrl.openConnection();
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            connection.setRequestProperty("Authorization", token);
            connection.connect();
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            //log.info("recv - {}", result);
        } catch (ConnectException e) {
            log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
        } catch (SocketTimeoutException e) {
            log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
        } catch (IOException e) {
            log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
        } catch (Exception e) {
            log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception ex) {
                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.toString();
    }

    /**
     * 向指定 URL 发送POST方法的请求
     * <p>
     * 注：此处加入Boolean stream 参数导致报错，无法使用
     *
     * @param url   发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendPost(String url, String param, String token) {
        PrintWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        try {
            //log.info("sendPost - {}", url);
            URL realUrl = new URL(url);
            URLConnection conn = realUrl.openConnection();
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setRequestProperty("Accept-Charset", Constants.UTF8);
            conn.setRequestProperty("contentType", "application/json");
            conn.setRequestProperty("Authorization", token);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            out = new PrintWriter(conn.getOutputStream());
            out.print(param);
            out.flush();
            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            //log.info("recv - {}", result);
        } catch (ConnectException e) {
            log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
        } catch (SocketTimeoutException e) {
            log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
        } catch (IOException e) {
            log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
        } catch (Exception e) {
            log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.toString();
    }

    /**
     * 向指定 URL 发送DELETE方法的请求
     *
     * @param url   发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendDelete(String url, String param, String token) {
        StringBuilder result = new StringBuilder();
        BufferedReader in = null;
        try {
            String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
            //log.info("sendDelete - {}", urlNameString);
            URL realUrl = new URL(urlNameString);
            HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setRequestProperty("Authorization", token);
            conn.setRequestMethod("DELETE");
            conn.connect();
            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            //log.info("recv - {}", result);
        } catch (ConnectException e) {
            log.error("调用HttpUtils.sendDelete ConnectException, url=" + url + ",param=" + param, e);
        } catch (SocketTimeoutException e) {
            log.error("调用HttpUtils.sendDelete SocketTimeoutException, url=" + url + ",param=" + param, e);
        } catch (IOException e) {
            log.error("调用HttpUtils.sendDelete IOException, url=" + url + ",param=" + param, e);
        } catch (Exception e) {
            log.error("调用HttpsUtil.sendDelete Exception, url=" + url + ",param=" + param, e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception ex) {
                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.toString();
    }

    /**
     * 向指定 URL 发送POST方法的请求
     *
     * @param url   发送请求的 URL
     * @param param 请求参数
     * @return 所代表远程资源的响应结果
     */
    public static String postData(String url, Map<String, Object> param, String token) {
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        log.info("postData - url: {} , param: {}", url, param);
        HttpPost post = new HttpPost(url);
        String result = "";
        try (CloseableHttpClient closeableHttpClient = httpClientBuilder.build()) {
            // 修复 POST json 导致中文乱码
            HttpEntity entity = new StringEntity(JSONObject.toJSONString(param), Constants.UTF8);
            post.setEntity(entity);
            post.setHeader("Authorization", token);
            post.setHeader("accept", "*/*");
            post.setHeader("connection", "Keep-Alive");
            post.setHeader("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            post.setHeader("Accept-Charset", Constants.UTF8);
            post.setHeader("Content-type", "application/json");
            post.setHeader("Authorization", token);
            HttpResponse resp = closeableHttpClient.execute(post);
            try {
                InputStream respIs = resp.getEntity().getContent();
                byte[] respBytes = IOUtils.toByteArray(respIs);
                result = new String(respBytes, StandardCharsets.UTF_8);
                //log.info("recv - {}", result);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 向指定 URL 发送PUT方法的请求
     *
     * @param url   发送请求的 URL
     * @param param 请求参数
     * @return 所代表远程资源的响应结果
     */
    public static String putData(String url, Map<String, Object> param, String token) {
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        //log.info("putData - {}", url);
        HttpPut put = new HttpPut(url);
        String result = "";
        try (CloseableHttpClient closeableHttpClient = httpClientBuilder.build()) {
            // 修复 POST json 导致中文乱码
            HttpEntity entity = new StringEntity(JSONObject.toJSONString(param), Constants.UTF8);
            put.setEntity(entity);
            put.setHeader("Authorization", token);
            put.setHeader("accept", "*/*");
            put.setHeader("connection", "Keep-Alive");
            put.setHeader("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            put.setHeader("Accept-Charset", Constants.UTF8);
            put.setHeader("Content-type", "application/json");
            put.setHeader("Authorization", token);
            HttpResponse resp = closeableHttpClient.execute(put);
            try {
                InputStream respIs = resp.getEntity().getContent();
                byte[] respBytes = IOUtils.toByteArray(respIs);
                result = new String(respBytes, StandardCharsets.UTF_8);
                //log.info("recv - {}", result);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

}
